﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FlexFlow.Common.Collections
{
    /// <summary>
    /// 为所有的自动清理集合提供基类
    /// </summary>
    public abstract class AutoClearnCollection
    {
        #region========私有变量========
        internal static ConcurrentQueue<IAutoClearnCollection> collections = new ConcurrentQueue<IAutoClearnCollection>();
        internal static Task clearTask = new Task(ClearLoop);
        #endregion
        #region==========属性==========
        /// <summary>
        /// 获取或设置自动清理的时间间隔
        /// </summary>
        public static int AutoClearnTick { get; set; }
        #endregion
        #region========私有方法========
        /// <summary>
        /// 表示清理循环
        /// </summary>
        private static void ClearLoop()
        {
            while (true)
            {
                System.Threading.Thread.Sleep(AutoClearnTick);
                IAutoClearnCollection col;
                int queueCount = collections.Count;
                int i = 0;
                while (i++ < queueCount && collections.TryDequeue(out col))
                {
                    lock (col.SyncRoot)
                    {
                        if (!col.IsDisposed)
                        {
                            col.Clearn();
                            collections.Enqueue(col);
                        }
                    }
                }
            }
        }
        #endregion
        #region========构造函数========
        /// <summary>
        /// 初始化自动清理集合的静态成员
        /// </summary>
        static AutoClearnCollection()
        {
            AutoClearnTick = 60000;
            clearTask.Start();
        }
        #endregion
    }
    /// <summary>
    /// 对集合提供自动清理及线程安全封装
    /// </summary>
    /// <typeparam name="T">
    /// 集合中元素的类型。
    /// </typeparam>
    /// <threadsafety static="true" instance="true"/>
    public class AutoClearnCollection<T> : AutoClearnCollection, ICollection<T>, IEnumerable<T>, IEnumerable, IAutoClearnCollection, IDisposable where T : IClearnable
    {
        #region========私有变量========
        private ConcurrentDictionary<T, T> items;
        private object syncRoot = new object();
        #endregion
        #region==========属性==========
        /// <summary>
        /// 获取 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 周围的 <see cref="System.Collections.Generic.IList&lt;T&gt;"/> 包装
        /// </summary>
        protected ICollection<T> Items { get { return items.Values; } }
        /// <summary>
        /// 表示该集合的线程同步操作锁对象
        /// </summary>
        public object SyncRoot
        {
            get { return syncRoot; }
        }
        /// <summary>
        /// 表示该集合是否已经被释放
        /// </summary>
        public bool IsDisposed
        {
            get;
            private set;
        }
        /// <summary>
        /// 表示该集合的用户定义数据
        /// </summary>
        public object Tag { get; set; }
        #endregion
        #region==========事件==========
        /// <summary>
        /// 表示当对象被清理之后引发的事件
        /// </summary>
        public event EventHandler<ObjectClearnEventArgs> AfterObjectClearn;
        #endregion
        #region========公有方法========
        /// <summary>
        /// 释放由<see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/>占用的所有资源
        /// </summary>
        public void Dispose()
        {
            lock (syncRoot)
            {
                this.items = null;
                this.IsDisposed = true;
                this.AfterObjectClearn = null;
            }
        }
        /// <summary>
        /// 执行一次清理操作，清理集合中超时的数据项
        /// </summary>
        /// <returns>
        /// 表示被清理的数据项集合
        /// </returns>
        public IEnumerable<IClearnable> Clearn()
        {
            lock (syncRoot)
            {
                List<IClearnable> res = new List<IClearnable>();
                foreach (var item in items)
                {
                    if (item.Value.NeedToClearn())
                    {
                        T clearnedItem = default(T);
                        items.TryRemove(item.Key, out clearnedItem);
                        res.Add(clearnedItem);
                    }
                }
                if (AfterObjectClearn != null)
                {
                    ObjectClearnEventArgs e = new ObjectClearnEventArgs(res);
                    AfterObjectClearn(this, e);
                }
                return res;
            }
        }
        /// <summary>
        /// 将对象添加到 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 的结尾处
        /// </summary>
        /// <param name="item">
        /// 要添加到 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 的末尾处的对象。 对于引用类型，该值可以为 null。
        /// </param>
        public void Add(T item)
        {
            if (items.ContainsKey(item))
            {
                throw new InvalidOperationException("指定对象在集合中已存在！");
            }
            items.TryAdd(item, item);
        }
        /// <summary>
        /// 从 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 中移除所有元素。
        /// </summary>
        public void Clear()
        {
            items.Clear();
        }
        /// <summary>
        /// 确定某元素是否在 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/>  中。
        /// </summary>
        /// <param name="item">
        /// 要在 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 中定位的对象。 对于引用类型，该值可以为 null。
        /// </param>
        /// <returns>
        /// 如果在 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 中找到 item，则为 true；否则为 false。
        /// </returns>
        public bool Contains(T item)
        {
            T gettedItem = default(T);
            return !items.TryGetValue(item, out gettedItem) && !gettedItem.NeedToClearn();
        }
        /// <summary>
        /// 从目标数组的指定索引处开始将整个 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 复制到兼容的一维 <see cref="System.Array"/>。
        /// </summary>
        /// <param name="array">
        /// 作为从 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 复制的元素的目标位置的一维 <see cref="System.Array"/>。 <see cref="System.Array"/> 必须具有从零开始的索引。
        /// </param>
        /// <param name="arrayIndex">
        ///  array 中从零开始的索引，从此索引处开始进行复制。
        /// </param>
        public void CopyTo(T[] array, int arrayIndex)
        {
            items.Values.CopyTo(array, arrayIndex);
        }
        /// <summary>
        /// 获取 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 中包含的有效元素数。
        /// </summary>
        public int Count
        {
            get
            {
                var res = items.Count(m => !m.Value.NeedToClearn());
                return res;
            }
        }
        /// <summary>
        /// 获取 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 中实际包含的元素数。
        /// </summary>
        public int PhysicalCount { get { return items.Count; } }
        /// <summary>
        /// 获取一个值，该值指示 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 是否为只读。
        /// </summary>
        public bool IsReadOnly
        {
            get { return false; }
        }
        /// <summary>
        /// 从 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/>中移除特定对象的第一个匹配项。
        /// </summary>
        /// <param name="item">
        /// 要从 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 中移除的对象。 对于引用类型，该值可以为 null。
        /// </param>
        /// <returns>
        /// 如果成功移除 item，则为 true；否则为 false。 如果在原始 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/>  中没有找到 item，此方法也会返回 false。
        /// </returns>
        public bool Remove(T item)
        {
            T gettedItem = default(T);
            return items.TryRemove(item, out gettedItem);
        }
        /// <summary>
        /// 返回循环访问 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 的枚举数。
        /// </summary>
        /// <returns>
        /// 用于 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 的 <see cref="System.Collections.Generic.IEnumerator&lt;T&gt;"/>。
        /// </returns>
        public IEnumerator<T> GetEnumerator()
        {
            var lst = from n in items
                      where !n.Value.NeedToClearn()
                      select n.Value;
            return lst.GetEnumerator();
        }
        /// <summary>
        /// 返回循环访问 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 的枚举数。
        /// </summary>
        /// <returns>
        /// 用于 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 的 <see cref="System.Collections.IEnumerator"/>。
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            var lst = from n in items
                      where !n.Value.NeedToClearn()
                      select n.Value;
            return lst.GetEnumerator();
        }
        #endregion
        #region========构造函数========
        /// <summary>
        /// 初始化为空的 <see cref="FlexFlow.Common.Collections.AutoClearnCollection&lt;T&gt;"/> 类的新实例。
        /// </summary>
        public AutoClearnCollection()
        {
            this.items = new ConcurrentDictionary<T, T>();
            collections.Enqueue(this);
        }
        #endregion

    }
}
